package com.jic.member.sms;


import com.jic.common.base.vo.RestResult;

import com.jic.common.redis.RedisClientTemplate;
import com.jic.member.constant.consist.ResponseCode;
import com.jic.member.exception.AppRuntimeException;
import com.jic.member.entity.SmsLog;
import com.jic.member.service.SmsLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

@Component
@Slf4j
public class GenerateSmsContent {

    @Resource
    private SmsLogService smsLogService;

    @Resource
    private RedisClientTemplate redissonClient;


    @Value("${sms.appkey}")
    private String appkey;
    @Value("${sms.appsecret}")
    private String appsecret;
    @Value("${sms.signName}")
    private String signName;
    @Value("${sms.uri}")
    private String uri;
    @Value("${sms.otp.expire.time}")
    private int expireTime;
    @Value("${sms.otp.template}")
    private String smsTemplate;
    @Value("${sms.otp.length}")
    private int otpLength;
    @Value("${sms.otp.more}")
    private int more;


    // OTP 短信模板
    private static final int TEMPLATE_TYPE = 0;
    // 缓存OTP code 后缀
    private static final String OTP_CODE_SUFFIX = "_OTP";
    // OTP 动态码数据源
    private static final String SMS_ORP_SOURCE = "1234567890";
    // 短信发送限制缓存后缀
    private static final String SMS_NUMBER_LIMIT_SUFFIX = "_limit";
    // 阿里OTP模板
    private static final String ALI_SMS_TEMPALTE_CODE = "SMS_145590139";

    /**
     * 发送短信
     *
     * @param smsSendRequest
     * @return
     * @throws Throwable
     */
    public RestResult sendSms(SmsSendRequest smsSendRequest) throws Throwable {
        Map<String, String> appVarMap = paramHandler(smsSendRequest);
        String phone = smsSendRequest.getPhone();
        String template = smsSendRequest.getTemplatCode();

        String smsContent = smsContentHandler(phone, template, appVarMap);

        AliyunSmsConfig smsConfig = new AliyunSmsConfig();
        smsConfig.setAccessKeyId(appkey);
        smsConfig.setSecret(appsecret);
        smsConfig.setSignName(signName);
        smsConfig.setTemplateCode(template);

        AliyunSmsCustomConfig customConfig = new AliyunSmsCustomConfig();
        customConfig.setPhone(phone);
        // 短信条数限制
        String moreLimitKey = phone+"_"+template;

        int cu_more = 0;
        if(redissonClient.get(moreLimitKey) !=null){
            cu_more = Integer.parseInt(redissonClient.get(moreLimitKey));
        }
        if(cu_more >= more){
            log.info("短信发送次数超限：{}",moreLimitKey);
            throw new AppRuntimeException("9999","短信发送次数过多");
        }
        AliSmsSendResponse b = AliyunSmsUtils.send(smsConfig, customConfig, appVarMap);
        Optional.ofNullable(b).orElseThrow(() -> new AppRuntimeException(ResponseCode.EXCEPTION));
        String code = b.getCode();

        if("OK".equalsIgnoreCase(code)){
            log.info("短信发送成功");
            redissonClient.set(moreLimitKey,String.valueOf(cu_more + 1));

            String key = phone + OTP_CODE_SUFFIX;
            String otp =redissonClient.get(key);
            // 短信发送记录存入发送历史表
            //记录短信验证码
            smsLogService.insert(new SmsLog() {{
                setCode(otp);
                setRetcode(code);
                setRetmsg(b.getMessage());
                setTelephone(smsSendRequest.getPhone());
                setStatus("0");
                setCreateTime(new Date());
            }});
            return RestResult.success("success");
        }else{
            log.info("短信发送失败");
            return RestResult.error("9999","短信发送失败");
        }
    }


    /**
     * 校验图形验证码发送短信
     * @param request
     * @return
     * @throws Throwable
     */
    public RestResult sendOtpSMS(SmsOtpRequest request) throws Throwable {
        String _vcode =redissonClient.get(request.getVtoken() + "_IMAGE_CODE");
        if(StringUtils.equalsIgnoreCase(_vcode, request.getVcode())){
            SmsSendRequest smsSendRequest = new SmsSendRequest();
            smsSendRequest.setPhone(request.getPhone());
            smsSendRequest.setTemplatCode(request.getTemplatCode());
            return sendSms(smsSendRequest);
        }else{
            return RestResult.error("9999","图形验证码错误");
        }
    }


    /**
     * 短信OTP验证
     *
     * @param smsVerifyRequest
     * @return
     */
    public RestResult verify(SmsVerifyRequest smsVerifyRequest) throws Throwable {

        String phone = smsVerifyRequest.getPhone();
        String otpCode = smsVerifyRequest.getOtpCode();
        // TODO 仅供测试使用
        if("6666".equals(otpCode)){
            return RestResult.success("0000");
        }

        String key = phone + OTP_CODE_SUFFIX;
        String otp =redissonClient.get(key);

        if (StringUtils.isEmpty(otp)) {
            throw new AppRuntimeException(ResponseCode.OTP_INCORRECT,"验证码错误，请重新发送");
        }
        if (StringUtils.equalsIgnoreCase(otp, otpCode)) {
            // 校验成功，删除code
          redissonClient.del(key);
            return RestResult.success("0000");
        } else {
            log.info("phone:{} verify invalid,otp code:{}", phone, otpCode);
            throw new AppRuntimeException(ResponseCode.OTP_INCORRECT,"验证码错误");
        }
    }

    /**
     * 处理前端传送的短信变量值
     *
     * @param smsSendRequest
     * @return
     */
    public Map<String, String> paramHandler(SmsSendRequest smsSendRequest) {
        Map<String, String> appVarMap = new HashMap<>();
        List<SmsVariable> smsVariableList = smsSendRequest.getSmsVariables();
        for (SmsVariable smsVariable : smsVariableList) {
            appVarMap.put(smsVariable.getKey(), smsVariable.getValue());
        }
        return appVarMap;
    }

    /**
     * 查询短信模板，填充动态变量
     *
     * @param templateCode
     * @param appVarMap
     * @return
     * @throws Throwable
     */
    private String smsContentHandler(String phone, String templateCode, Map<String, String> appVarMap) throws Throwable {
        // 判断短信模板类型
        if (StringUtils.equals(smsTemplate,templateCode)) {
            String otp = createOtp(otpLength);
            // 验证码放入redis
            String key = phone + OTP_CODE_SUFFIX;
            redissonClient.setex(key,expireTime,otp);
            appVarMap.put("code", otp);
        }
        String msgContent = phone+":"+templateCode+":"+appVarMap.get("code");
        return msgContent;
    }

    /**
     * 生成OTP
     *
     * @param otpCodelenth
     * @return OTP
     * @throws Exception
     */
    public String createOtp(int otpCodelenth) throws Throwable {
        String otpsrc = SMS_ORP_SOURCE;
        String otp = generateMixString(otpCodelenth, otpsrc);
        if (otp.length() > otpCodelenth) {
            otp = generateMixString(otpCodelenth, otpsrc);
        }
        return otp;
    }

    /**
     * 返回一个定长的随机字符串
     *
     * @param length 随机字符串长度
     * @return 随机字符串
     */
    private String generateMixString(int length, String source) {
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(source.charAt(random.nextInt(source.length())));
        }
        return sb.toString();
    }
}
